﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;//添加命名空间(串口通讯)
using System.Threading;

namespace SerialHelper
{
    /// <summary>
    /// 发生接收模式16进制/字符串
    /// </summary>
    public enum ComMode
    {
        Hexadecimal,//16进制
        CharacterString//字符串
    }

    /// <summary>
    /// 微软自带串口类
    /// </summary>
    public class ComHelper
    {
        public string _PortName;
        public int _BaudRate;
        public int _DataBits;
        public Parity _Parity;
        public StopBits _StopBits;

        public SerialPort _SerialPort = new SerialPort();//串口资源
        CancellationTokenSource _ConnState;//检测串口在线循环条件
        Thread _ConnThread;
        bool Closeing = false;
        /// <summary>
        /// 是否开启
        /// </summary>
        public bool IsOpen
        {
            get { return _SerialPort.IsOpen; }
        }

        /// <summary>
        /// 是否在线
        /// </summary>
        public bool IsConnection { get; set; }


        ComMode Mode;//模式
        public delegate void OnReceiveMessageDelegate(string Message);
        public event OnReceiveMessageDelegate OnReceiveMessage;//接收事件


        #region 打开串口
        //案例："COM2",9600,8,System.IO.Ports.Parity.None,System.IO.Ports.StopBits.One
        public ComHelper(string PortName, int BaudRate, int DataBits, Parity Parity, StopBits StopBits, ComMode Mode = ComMode.CharacterString)
        {
            this.Mode = Mode;
            _PortName = PortName;
            _BaudRate = BaudRate;
            _DataBits = DataBits;
            _Parity = Parity;
            _StopBits = StopBits;
        }
        #endregion

        #region 开启
        /// <summary>
        /// 开启
        /// </summary>
        /// <returns></returns>
        public bool Open()
        {

            if (_SerialPort == null)
            {
                return false;
            }
            if (!_SerialPort.IsOpen)//开启
            {
                try
                {
                    _SerialPort.PortName = _PortName;
                    _SerialPort.BaudRate = _BaudRate;
                    _SerialPort.DataBits = _DataBits;
                    _SerialPort.Parity = _Parity;
                    _SerialPort.StopBits = _StopBits;
                    _SerialPort.ReceivedBytesThreshold = 1;//每当有一个字节进缓冲区就进入接收事件相应方法
                    _SerialPort.DataReceived += NowRead;//读取事件绑定
                    _SerialPort.Open();

                    if (_ConnThread == null || !_ConnThread.IsAlive)
                    {
                        _ConnState = new CancellationTokenSource();
                        _ConnThread = new Thread(ConnThread);
                        _ConnThread.Start();//开启检测在线线程
                    }




                    //流控制(分软件控制与硬件控制)硬件不用设置
                    //_SerialPort.RtsEnable = true;
                    //_SerialPort.DtrEnable = true;
                }
                catch
                {
                    return false;
                }
            }
            return true;
        }

        #endregion

        #region 关闭服务
        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <returns></returns>
        public bool Close()
        {


            if (_SerialPort == null)
            {
                return false;
            }

            if (_SerialPort.IsOpen)//开启
            {
                Closeing = true;
                try
                {
                    IsConnection = false;
                    _ConnState.Cancel();//关闭检测在线线程

                    Thread.Sleep(100);

                    // _SerialPort.DiscardInBuffer();
                    _SerialPort.Close();
                    IsConnection = false;
                }
                catch
                {
                    return false;
                }
            }
            Closeing = false;
            return true;


        }
        #endregion

        #region 发送
        /// <summary>
        /// 发送
        /// </summary>
        /// <param name="Message"></param>
        /// <returns></returns>
        public string Sending(string Message)
        {
            string Error = string.Empty;
            try
            {
                if (Mode == 0)//16进制模式发送
                {
                    //''FF 01 00 02 40 00 43"-->255 1 0 2 64 0 67
                    byte[] SendMessage = HexToIntByte(Message);
                    _SerialPort.Write(SendMessage, 0, SendMessage.Length);//写入串口缓冲区
                }
                else//字符串进制模式发送
                {
                    byte[] SendMessage = Encoding.UTF8.GetBytes(Message);
                    _SerialPort.Write(SendMessage, 0, SendMessage.Length);//写入串口缓冲区
                }

            }
            catch (Exception ex)
            {
                Error = ex.Message;
            }
            return "True";

        }
        #endregion

        #region 数据转换
        //字符串-->16进制-->10进制-->byte[]
        public byte[] HexToIntByte(string Text)
        {
            Console.WriteLine(Text);
            Text = Text.Replace(" ", "");
            Console.WriteLine(Text);
            Text = Text.Replace("0X", "");
            Console.WriteLine(Text);

            if (Text.Length / 2 != 0)
            {
                Text += "";
            }

            byte[] ByteResult = new byte[Text.Length / 2];
            for (int i = 0; i < Text.Length / 2; i++)
            {
                ByteResult[i] = Convert.ToByte(Text.Substring(i * 2, 2), 16);//将值转换成8位数值,后面的值为前面值的进制;Convert.ToByte(值,进制)
            }
            return ByteResult;

        }

        //byte[]-->10进制-->16进制-->字符串
        public string BytesToHexStr(byte[] beff)
        {
            string str = string.Empty;
            for (int i = 0; i < beff.Length; i++)
            {
                str += beff[i].ToString("X2");//10进制-->16进制(字符串转换对等的大小)
                str += "";
            }
            return str;
        }

        #endregion

        #region 读取数据(事件)
        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void NowRead(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                if (_SerialPort == null)
                {
                    return;
                }
                if (Closeing)
                {
                    return;
                }
                if (!IsConnection)
                {
                    return;
                }
                string hexStr;
                int count = _SerialPort.BytesToRead;//读取缓存区的字节大小
                System.Threading.Thread.Sleep(20);
                byte[] beff = new byte[count];
                _SerialPort.Read(beff, 0, count);//把缓存区的数据存入数组中
                if (beff == null)
                {
                    return;
                }
                if (beff.Length == 0)
                {
                    return;
                }
                if (Mode == 0)//16进制
                {
                    hexStr = BytesToHexStr(beff);//10进制数组-->16进制字符串
                }
                else//字符串
                {
                    hexStr = Encoding.Default.GetString(beff);

                }
                Task.Run(() =>
                {
                    OnReceiveMessage?.Invoke(hexStr);
                });
            }
            catch (Exception)
            {
            }
        }
        #endregion

        #region 检测在线线程
        public void ConnThread()
        {
            Task task = new Task(() =>
            {
                try
                {
                    while (!_ConnState.IsCancellationRequested)
                    {
                        bool ConnTemp = false;
                        string[] gCOM = System.IO.Ports.SerialPort.GetPortNames(); // 获取设备的所有可用串口
                        int j = gCOM.Length; // 得到所有可用串口数目
                        for (int i = 0; i < j; i++)
                        {
                            if (gCOM[i] == _SerialPort.PortName)
                            {
                                ConnTemp = true;
                            }
                        }
                        if (ConnTemp)
                        {
                            if (IsOpen)
                            {
                                IsConnection = true;
                            }
                            else
                            {
                                IsConnection = false;
                            }
                        }
                        else
                        {
                            IsConnection = false;
                        }
                        Thread.Sleep(1500);
                    }
                }
                catch (Exception)
                {

                    throw;
                }

            });
            task.Start();
        }
        #endregion
    }
}
